package com.netsar.parser;

import java.io.ByteArrayInputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpHost;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.netsar.modelo.Cidade;
import com.netsar.modelo.Reservas;



/**
 * Classe responsavel por tratar os aquivos XML e envia-los/recebe-los do webservice
 *
 */
public class LeitorXML{
	
	
	private static LeitorXML leitorXml;  

	public static final LeitorXML getInstance() {  
		if (leitorXml == null) {  
			leitorXml = new LeitorXML();  
		}  
		return leitorXml;  
	}  
	

	/**
	 * Realiza a leitura do arquivo XML informado como parametro
	 * @param  arquivo XML
	 * @return lista de todos codigos de hoteis contidos no arquivo XML
	 */
	public List<Integer> realizaLeituraXMLRecuperaCodigoHoteis(String arquivoXML, String elementoFilho){
		
		NodeList listaObjetos = localizaElementosFilhos(arquivoXML,	elementoFilho);
		List<Integer> lista = new ArrayList<Integer>(listaObjetos.getLength());

		//Obtem os elementos de cada elemento do hotel
		for (int i=0; i<listaObjetos.getLength(); i++){
			Element elementoHotel = (Element) listaObjetos.item(i);
			Integer codigoHotel = Integer.valueOf(obterValorElemento(elementoHotel,"kr:hotelCode"));
			lista.add(codigoHotel);
		}

		return lista;
	}

	/**
	 * Realiza a leitura do arquivo XML informado como parametro
	 * @param  arquivo XML
	 * @return lista de hoteis contidos no arquivo XML
	 */
	public List<Reservas> realizaLeituraXMLPesquisa(Date dataCheckin, Date dataCheckout,Integer codigoCidade){
		
		
		String xmlPesquisa = montaArquivoXMLPesquisa(dataCheckin, dataCheckout, codigoCidade);
		String xmlResponse = getXMLResponse(xmlPesquisa);
		
		NodeList listaObjetos = localizaElementosFilhos(xmlResponse, "kr:hotelAvailabilityResponse");
		
		List<Reservas> lista = new ArrayList<Reservas>(listaObjetos.getLength());

		//Obtem os elementos de cada elemento do hotel
		for (int i=0; i<listaObjetos.getLength(); i++){
			Element elementoHotel = (Element) listaObjetos.item(i);
			Reservas reserva = preencheDadosHotel(elementoHotel);
			lista.add(reserva);
		}

		return lista;
	}

	
	
	
	
	/**
	 * Realiza a leitura do arquivo XML informado como parametro
	 * @param  arquivo XML
	 * @return lista de cidades contidos no arquivo XML
	 */
	public List<Cidade> realizaLeituraXMLCidades(){
		
		String arquivoXML = montaArquivoXMLCidades();
		String xmlResponse = getXMLResponse(arquivoXML);
		
		NodeList listaObjetos = localizaElementosFilhos(xmlResponse, "ns:cityCodes");
		List<Cidade> lista = new ArrayList<Cidade>(listaObjetos.getLength());

		//Obtem os elementos de cada elemento do hotel
		for (int i=0; i<listaObjetos.getLength(); i++){
			Element elementoCidade = (Element) listaObjetos.item(i);
			Cidade cidade = preencheCidades(elementoCidade);
			lista.add(cidade);
		}

		return lista;
	}
	
	
	
	
	
	
	private Cidade preencheCidades(Element elementoCidade) {

		Cidade cidade = new Cidade();
		String codigoCidade = obterValorElemento(elementoCidade,"ns:code");
		if(codigoCidade != null){
			cidade.setCodigo(Integer.valueOf(codigoCidade));
			cidade.setNomeCidade(obterValorElemento(elementoCidade,"ns:name"));
		}
		return cidade;
	}


	private NodeList localizaElementosFilhos(String arquivoXML, String elementoFilho)  {

		//faz o parse do arquivo e cria o documento XML
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = null;
		Document doc = null;
		try{
			db = dbf.newDocumentBuilder();
			doc = db.parse(new ByteArrayInputStream(arquivoXML.getBytes()));
		}catch (Exception e) {
			e.printStackTrace();
		}
		//obtem o elemento raiz
		Element raiz = doc.getDocumentElement();

		//localiza os elementos filhos
		NodeList listaObjetos = raiz.getElementsByTagName(elementoFilho);

		return listaObjetos;
	}
	
	
	private Reservas preencheDadosHotel(Element elemento){

		Reservas reservaHotel = new Reservas();
		SimpleDateFormat  sdf = new SimpleDateFormat("yyyy-MM-dd");
		String dataInicio = obterValorElemento(elemento,"kr:checkInDate");
		String dataFim = obterValorElemento(elemento,"kr:checkOutDate");
		String codigoCidade = obterValorElemento(elemento,"kr:cityCode");
		reservaHotel.setNomeCidade(obterValorElemento(elemento,"kr:cityName"));
		reservaHotel.setCodigoCidade(codigoCidade != null ? Integer.parseInt(codigoCidade): null);
		
		//TODO //////////////////////////////////////////////////////////////////
		obterValorElemento(elemento,"kr:availableHotelType");
		  reservaHotel.setNomeHotel(obterValorElemento(elemento,"kr:hotelName"));
		//  reservaHotel.setCodigoHotel(obterValorElemento(elemento,"kr:hotelCode"));

		try {
			if(dataInicio != null)
				reservaHotel.setDataInicio(sdf.parse(dataInicio));
			if(dataFim != null)
				reservaHotel.setDataFim(sdf.parse(dataFim));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return reservaHotel;
	}
	
	
	
	

	/**
	 * Obtem o valor do Text Node de um determinado elemento (se este 
	 * possuir um valor)
	 * @param elemento objeto que deseja-se obter o valor
	 * @param nomeElemento nome da tag cujo valor deseja-se obter
	 * @return valor da tag/elemento se esta existir ou null caso nao exista
	 */
	public String obterValorElemento(Element elemento, String nomeElemento){
		//obtem a lista de elementos
		NodeList listaElemento = elemento.getElementsByTagName(nomeElemento);
		if (listaElemento == null){
			return null;
		}
		//obtem o elemento
		Element noElemento = (Element) listaElemento.item(0);
		if (noElemento == null){
			return null;
		}
		//obtem o no com a informacao
		Node no = noElemento.getFirstChild();
		return no != null ? no.getNodeValue() : null;
	}

	public static void main(String[] args){
		LeitorXML  parser =  new  LeitorXML ();
		List<Reservas> listaHoteis = parser.realizaLeituraXMLPesquisa(new Date("2002/04/01"),new Date("2012/04/31"),40);
//		parser.realizaLeituraXMLCidades();
		for (Reservas contato : listaHoteis)
			System.out.println(contato.getCodigoHotel());
	}
	
	
	private String montaArquivoXMLPesquisa(Date dataCheckin,
			Date dataCheckout, Integer codigoCidade){

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

		StringBuffer xmlPesquisa = new StringBuffer();
		xmlPesquisa.append("<?xml version='1.0' encoding='UTF-8'?>");
		xmlPesquisa.append("<kr:kobraRequest xmlns:kr='http://kobra.kuoni.com/xml'>");
		xmlPesquisa.append("<kr:requestHeader>");
		xmlPesquisa.append("<kr:userId>agent</kr:userId>");
		xmlPesquisa.append("<kr:password>test</kr:password>");
		xmlPesquisa.append("</kr:requestHeader>");
		xmlPesquisa.append("<kr:data>");
		xmlPesquisa.append("<kr:hotelAvailabilityRequest>");
		xmlPesquisa.append("<kr:cityCode>"+codigoCidade+"</kr:cityCode>");
		xmlPesquisa.append("<kr:checkInDate>"+sdf.format(dataCheckin)+"</kr:checkInDate>");
		xmlPesquisa.append("<kr:checkOutDate>"+sdf.format(dataCheckout)+"</kr:checkOutDate>");
		xmlPesquisa.append("<kr:hotelName/>");
		xmlPesquisa.append("<kr:locationCode/>");
		xmlPesquisa.append("<kr:categoryCode />");
		xmlPesquisa.append("<kr:onlyConfirmed>false</kr:onlyConfirmed>");
		xmlPesquisa.append("<kr:requestDynamicRates>true</kr:requestDynamicRates>");
//		xmlPesquisa.append("<kr:requestedRoomUse>");
//		xmlPesquisa.append("<kr:roomUseCode>6</kr:roomUseCode>");    
//		xmlPesquisa.append("<kr:numberOfRooms>1</kr:numberOfRooms>"); 
//		xmlPesquisa.append("</kr:requestedRoomUse>");
		xmlPesquisa.append("<kr:hideCancellationDeadline>true</kr:hideCancellationDeadline>");
	    xmlPesquisa.append("<kr:hideExceptions>true</kr:hideExceptions>");
		xmlPesquisa.append("</kr:hotelAvailabilityRequest>");
		xmlPesquisa.append("</kr:data>");
		xmlPesquisa.append("</kr:kobraRequest>");
		
		
		
/*		
		<kr:kobraRequest xmlns:kr="http://kobra.kuoni.com/xml">
		  <kr:requestHeader>
		    <kr:userId>agent</kr:userId>
		    <kr:password>test</kr:password>
		  </kr:requestHeader>
		  <kr:rqData>
		    <kr:hotelAvailabilityRequest>
		      <kr:cityCode>531</kr:cityCode>
		      <kr:checkInDate>2010-08-10</kr:checkInDate>
		      <kr:checkOutDate>2010-08-12</kr:checkOutDate>
		      <kr:hotelName></kr:hotelName>
		      <kr:locationCode>0</kr:locationCode>
		      <kr:categoryCode>0</kr:categoryCode>
		      <kr:onlyConfirmed>false</kr:onlyConfirmed>
		      <kr:requestedRoomUse>
		        <kr:roomUseCode>6</kr:roomUseCode>
		        <kr:numberOfRooms>1</kr:numberOfRooms>
		      </kr:requestedRoomUse>
		    </kr:hotelAvailabilityRequest>
		  </kr:rqData>
		</kr:kobraRequest>*/
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		return xmlPesquisa.toString();

	}
	
	

	
	
	private String montaArquivoXMLCidades(){

		StringBuffer xmlCodigos = new StringBuffer();

		xmlCodigos.append("<?xml version='1.0'?>");
		xmlCodigos.append("<kr:kobraRequest xmlns:kr='http://kobra.kuoni.com/xml'>");
		xmlCodigos.append("<kr:requestHeader>");
		xmlCodigos.append("<kr:userId>agent</kr:userId>");
		xmlCodigos.append("<kr:password>test</kr:password>");
		xmlCodigos.append("</kr:requestHeader>");
		xmlCodigos.append("<kr:rqData>");
		xmlCodigos.append("<kr:provideKobraCodesRequest>");
		xmlCodigos.append("</kr:provideKobraCodesRequest>");
		xmlCodigos.append("</kr:rqData>");
		xmlCodigos.append("</kr:kobraRequest>");

		return xmlCodigos.toString();

	}
	
	
	
	
	/**
	 * Realiza conexao com webservice
	 * @param arquivo xml de requisicao
	 * @return arquivo xml retornado pelo webservice
	 */
	public String getXMLResponse(String strXMLRequest){

		// Prepare HTTP post
		String strURL = "http://login.kuoni-connect.com/kobraedu/";
//		String strURL = "http://zip.kuoni-connect.com/kobra";
		try
		{
			PostMethod post = new PostMethod(strURL);
			post.setRequestBody(new ByteArrayInputStream(strXMLRequest.getBytes()));
			post.setRequestContentLength((int)strXMLRequest.length());
			post.setRequestHeader("Content-type", "text/xml; charset=UTF-8");  

			HttpClient httpclient = new HttpClient();
			Integer result = httpclient.executeMethod(post);

			if (result != 200)
				return result != null ? result.toString() : null;

			String strXMLResponse = post.getResponseBodyAsString();

			InputSource is = new InputSource( post.getResponseBodyAsStream() );

			Document doc = null;

			try
			{
				DocumentBuilder docBuilder =
					DocumentBuilderFactory.newInstance().newDocumentBuilder();
				doc = docBuilder.parse(is);
			}
			catch( Exception e )
			{
				throw new RuntimeException("Could not parse server START response");
			}
			post.releaseConnection();  

			return strXMLResponse;

		}
		catch( Exception ex )
		{
			System.out.println( ex.getMessage() );
		}		

		return null;

	}







}
